/*  The author disclaims copyright to this source code.  In place of a legal notice, here is a blessing:
       May you do good and not evil.
       May you find forgiveness for yourself and forgive others.
       May you share freely, never taking more than you give.
*/
package com.googlecode.droidjni;

import java.io.*;
import java.util.*;

@SuppressWarnings({"unused"})
public class util {

    private util() {}

    public static void assertion(boolean b) {
        if (!b) {
            trace("assertion failed");
            rethrow(new AssertionError());
        }
    }

    public static void assertion(boolean b, String msg) {
        if (!b) {
            trace("assertion " + msg + " failed");
            rethrow(new AssertionError(msg));
        }
    }

    public static void rethrow(Throwable t) {
        if (t != null) {
            throw t instanceof Error ? (Error)t : new Error(t);
        }
    }

    public static void trace(String... params) {
        if (params != null && params.length > 0) {
            trace0(getCallersCaller(), params);
        }
    }

    public static void trace(Throwable t) {
        trace(t, new String[]{null});
    }

    public static String getCallersCaller() {
        StackTraceElement st = Thread.currentThread().getStackTrace()[4];
        return forName(st.getClassName()).getSimpleName() + "." + st.getMethodName() +
                                ":" + st.getLineNumber() + " ";
    }

    public static Class<?> forName(String n) {
        try {
            return n == null ? null : Class.forName(n);
        } catch (ClassNotFoundException e) {
            return null;
        }
    }

    public static void trace(Throwable t, String... params) {
        ByteArrayOutputStream ba = new ByteArrayOutputStream();
        PrintStream ps = new PrintStream(ba);
        if (params != null && params.length > 0) {
            for (String p : params) {
                if (p != null) {
                    ps.print(p);
                    ps.print(' ');
                }
            }
            ps.println();
        }
        t.printStackTrace(ps);
        ps.close();
        trace(ba.toString());
    }

    public static void trace0(String caller, String... params) {
        if (params != null && params.length > 0) {
            StringBuilder sb = new StringBuilder(params[0].length() * 2);
            sb.append(caller).append(' ');
            for (String p : params) {
                if (p != null) {
                    sb.append(p).append(' ');
                }
            }
            String s = sb.toString().trim();
            android.util.Log.d(droid.LOG_TAG, s);
//          System.err.println(s);
        }
    }

    private static HashMap<String, Long> start = new HashMap<String, Long>();
    private static long self_time; // = 0
    private static boolean trace_timestamp;

    public synchronized static long timestamp(String label) { // returns delta in nanoseconds
        if (self_time == 0) {
            self_time = 1;
            timestamp("timestamp-self-delta");
            self_time = timestamp("timestamp-self-delta");
            if (self_time <= 0) {
                self_time = 1;
            }
            trace_timestamp = true;
        }
        long t = System.nanoTime();
        Long s = start.remove(label);
        if (s == null) {
            start.put(label, t);
            return 0;
        } else {
            long delta = t - s;
            delta = delta < 1 ? 1 : delta;
            if (trace_timestamp) {
                trace0(getCallersCaller(), "time: \"" + label + "\" " + humanReadable(delta));
            }
            return delta;
        }
    }

    public static String humanReadable(long delta) {
        if (delta < 10L * 1000) {
            return delta + " nanoseconds";
        } else if (delta < 10L * 1000 * 1000) {
            return delta / 1000 + " microseconds";
        } else if (delta < 10L * 1000 * 1000 * 1000) {
            return delta / (1000 * 1000) + " milliseconds";
        } else {
            return delta / (1000 * 1000 * 1000) + " seconds";
        }
    }

}
